home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


Note that when subroutine LogError exits, Visual Basic clears the Err object. If RiskySub needs to use the Err.Number and Err.Description values later, it must save those values before it calls LogError.

Private Sub RiskySub()
Dim err_number As Long
Dim err_description As String

    On Error GoTo Error1
    ' Do something that might cause an error.
        :
    Exit Sub

Error1:
    ' Save the error values because they will be
    ' cleared when we successfully call LogError.
    err_number = Err.Number
    err_description = Err.Description

    ' LogError logs the error safely, protecting
    ' us with its own On Error statement.
    LogError err_number, "MyApp.RiskySub", err_description

    ' Reraise the error.
    Err.Raise err_number, _
        "MyApp.RiskySub", _
        err_description
End Sub

Private Sub LogError(ByVal err_number As Long, _
    ByVal err_source As String, ByVal err_description As String)

    ' Make sure we do not fail.
    On Error Resume Next

    ' Log the error.
        :
End Sub

Always Be Prepared

Errors can happen at practically any time. Even if the program is completely bug free, there are parts of the environment that are outside of the program’s control. The user might have several memory-intensive programs running and they may prevent your program from allocating the memory it needs. The user might open a floppy drive door while your program is trying to read from that drive. A word processor might have locked a file the program needs.

The program must always be prepared to handle unexpected errors. During the design phase, the program can stop so you can identify the problem. In its final compiled version, the program should record the error and continue as gracefully as possible.

Being always prepared for failure means the program must always have an error handler registered and ready to run. At a minimum, all event handlers and the Main subroutine must use error handling. Most programs should also handle errors in other subroutines at a more local scope instead of letting them propagate all the way up the call stack to the event handlers.

Event handlers must be prepared to handle every kind of error. A routine may generate an error directly, or a subroutine it calls may generate the error. The event handler should record and handle the error smoothly if possible. It should at least catch the error and ignore it so the program can continue running.

Clean Up

When a routine fails during the project’s design phase, it should stop and alert you to the problem. In the final compiled version, the program should continue running as normally as possible. Continuing could be extremely difficult if the routine that fails leaves the program in some uncertain state.

To allow the program to keep running, a routine that fails should clean up any mess it has made. It should restore global variables and data structures to the state they were in before the routine began. The calling routine can then assume the routine is either successful or that it cleans up its mess.

If a routine’s failure means the calling routine cannot continue properly, it should also undo any changes it has made. It can then fail and return control to the routine that called it.

In the worst case, when none of the routines can continue executing, control passes all the way back to the event handler that started the action. If the event handler fails, the program must ignore the event. The behavior the user wanted to trigger will not occur, but otherwise the program should continue normally.

For instance, suppose the user clicks on a button that starts a complex process. Somewhere deep within the series of subroutine calls, an unrecoverable error occurs. As each subroutine fails, it cleans up after itself. Control eventually returns to the button’s Click event handler. The error handling code in that routine displays a message telling the user that the program cannot perform the desired task, and then it exits. Control returns to Visual Basic’s event handling loop and the program is ready to run as if the user had never clicked the button. The rest of the program’s code can run safely because each of the routines that failed cleaned up their messes.

For a more complex example, suppose a program uses an object of the DispatchScenario class named TheScenario to store information about a dispatching system. The LoadScenario subroutine that follows loads data about a particular dispatch problem from a file into a new DispatchScenario object. If the routine fails, it destroys the new DispatchScenario object it has created. It calls the DestroyScenario subroutine to destroy the pieces of the data structure. This leaves the program as it was before the routine was called so the program can continue running.

Only if the routine successfully creates the new scenario object does it destroy the old object and replace it with the new one.


' Global DispatchScenario object.
Private TheScenario As DispatchScenario

' Define error constants.
Private Const myappErrScenarioFileNotFound = 1
    :

' Load a dispatch scenario from a file.
Private Sub LoadDispatchScenario(ByVal file_name As String)
Dim new_scenario As DispatchScenario
Dim file_number As Integer
        :
Dim err_number As Long
Dim err_description As String

    ' Open the file.
    On Error GoTo FileOpenError
    file_number = FreeFile
    Open file_name For Input As file_number
        :
    ' Create the new scenario object.
    Set new_scenario = New DispatchScenario

    ' Read the data from the file.
    On Error GoTo FileReadError
        :
    ' Close the file.
    Close file_number

    ' We have successfully created the new
    ' scenario object. Destroy the old one and
    ' replace it with the new object.
    DestroyScenario TheScenario
    Set TheScenario = new_scenario
    Exit Sub

FileOpenError:
    ' Raise a new error.
    Err.Raise myappErrScenarioFileNotFound, _
        "MyApp.LoadDispatchScenario", _
        "Could not open scenario file """ & _
        file_name & """." & vbCrLf & Err.Description
    Exit Sub

FileReadError:
    err_number = Err.Number
    err_description = _
        "Could not read scenario file """ & _
        file_name & """." & vbCrLf & Err.Description

    ' Close the file.
    Close file_number

    ' Destroy the objects created so far.
    DestroyScenario new_scenario
    Set new_scenario = Nothing

    ' Raise a new error.
    Err.Raise err_number, _
        "MyApp.LoadDispatchScenario", _
        err_description
    Exit Sub
End Sub

Handle Errors in Objects

A program’s code is executed directly or indirectly from its event handlers and from the Main subroutine if one is installed. The program can use normal error handlers to catch and handle errors that occur within this code.

However, there are times when code is not under the direct control of the program. For example, suppose you have built an ActiveX control using Visual Basic 5 or 6. That control might contain a Timer control with a Timer event handler that generates an error under certain circumstances. That event is independent of the main program, so the program cannot trap any errors it generates. If the Timer event raises an error, the program crashes.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.